package icraf.carbon.gui.model;

import icraf.carbon.core.Project;
import icraf.carbon.core.Zone.DataType;
import icraf.carbon.gui.LCMatrixTabPanel;
import icraf.carbon.gui.MenuFactory;
import icraf.carbon.gui.ProjectDockListener;
import icraf.carbon.gui.ProjectPanelEvent;
import icraf.carbon.gui.ProjectTreePanel;
import icraf.carbon.gui.MenuFactory.MenuProperty;
import icraf.carbon.model.AbacusModel;
import icraf.carbon.model.ModelProject;
import icraf.common.gui.MenuAdapter;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

public class ModelScenarioPanel extends ModelIterationPanel {
	private boolean isEnableMenu = true;

	public class Listener extends MouseAdapter implements ActionListener,
			TableModelListener, ProjectDockListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			if (MenuProperty.MODEL_UNCONVERTED.isAction(e)) {
				setUnconvertedLanduse();

			} else if (e.getSource().equals(updateButton)) {
				updateModelScenario();
			}
		}

		@Override
		public void mouseReleased(MouseEvent e) {
			if (e.isPopupTrigger()||e.isControlDown()||e.getButton()==MouseEvent.BUTTON3) {
				if(isEnableMenu)
				popMenu.show((Component) e.getSource(), e.getX(), e.getY());
			}
			JList<?> l = (JList<?>) e.getSource();
			selectedIndex = l.locationToIndex(e.getPoint());
		}

		@Override
		public void tableChanged(TableModelEvent e) {
			if (e.getColumn() >= 0) {
				updateLabel();
			}
		}

		@Override
		public void projectSelectionChanged(ProjectPanelEvent e) {
			if ((e.getProperties() != MenuProperty.MODEL_TPM && e
					.getProperties() != MenuProperty.MODEL_LANDUSE_SCENARIO)) { 
				checkLeaveScenario();
			}
			if (e.getProperties() == MenuProperty.MODEL_TPM
					|| e.getProperties() == MenuProperty.MODEL_LANDUSE_SCENARIO) {
				checkUpdatedScenario(e.getProperties());
			}
		}

		@Override
		public void projectPopupTriggered(ProjectPanelEvent e,
				Component invoker, int x, int y) {
		}

		@Override
		public void projectDoubleClicked(ProjectPanelEvent e) {
		}
	}

	private static final long serialVersionUID = -8058181765772089678L;
	private static String scenarioChange = " "+MenuProperty.MODEL_SCENARIO_CHANGE.getLabel()+ ": ";
	private static String scenarioChange2 = ", "+MenuProperty.MODEL_SCENARIO_CHANGE.getAccessibleDescription()+ "->";

	private boolean isScenarioUpdated = false;
	private Listener listener = new Listener();
	private JPopupMenu popMenu = new JPopupMenu();
	private int selectedIndex;
	private JButton updateButton;
	private JLabel warningLabel;
	private int updatedPeriod = -1;
	private int selectedPeriodIdx;
	private int updatedIndex = -1;
	private ModelPanel modelPanel;
	private ProjectTreePanel projectTreePanel;
	private DataType dataType;
	private ModelProject updatedModel;

	public ModelScenarioPanel(ModelPanel modelPanel) {
		this.modelPanel = modelPanel;
		popMenu.add(MenuFactory.createMenuItem(MenuProperty.MODEL_UNCONVERTED,
				listener));
		setRowMouseListener(listener);
		setTableModelListener(listener);

		updateButton = new JButton(MenuProperty.MODEL_SCENARIO_BUTTON.getLabel());
		updateButton.addActionListener(listener);
		updateButton.setEnabled(false);
		warningLabel = new JLabel();
		warningLabel.setOpaque(true);
		warningLabel.setBackground(Color.red);
		warningLabel.setForeground(Color.white);
		JPanel pb = new JPanel();
		pb.add(warningLabel);
		pb.add(updateButton);
		this.add(pb, BorderLayout.NORTH);
	}

	public boolean checkLeaveScenario() {
		if (updatedIndex >= 0) {
			JOptionPane
					.showMessageDialog(this,
							MenuProperty.MODEL_SCENARIO_BUTTON.getAccessibleDescription());
			projectTreePanel.setSelection(updatedModel.getMainProject(),
					MenuProperty.MODEL_TPM);
			return false;
		}
		return true;
	}

	public void checkUpdatedScenario(MenuAdapter mp) {
		int updIdx = modelPanel.getUpdatedIndex();
		if (updIdx >= 0) {
			updatedIndex = updIdx;
			updatedPeriod = Integer.parseInt(getTabPanel().getTitleAt(
					updatedIndex));
			warningLabel.setText(scenarioChange + updatedPeriod
					+ scenarioChange2);
			DataType updater = modelPanel.getUpdaterType();

			if (mp == MenuProperty.MODEL_TPM
					&& dataType == DataType.TPM_SCENARIO
					&& updater != DataType.TPM_SCENARIO) {
				if (!modelPanel.checkLUS()) {
					JOptionPane
							.showMessageDialog(
									this,
									MenuProperty.MODEL_SCENARIO_INVALID.getAccessibleDescription(),
									MenuProperty.MODEL_SCENARIO_INVALID.getLabel(),
									JOptionPane.WARNING_MESSAGE);
				}
				
				ModelProject m = modelPanel.getProject().getModelProject();
				for (int i = 0; i < m.getIterationCount(); i++) {
					Project p = m.getSimulatedProject(i);
					AbacusModel.updateTPMbyLanduseScenario(p);
				}
			} else if (mp == MenuProperty.MODEL_LANDUSE_SCENARIO
					&& dataType == DataType.LANDUSE_SCENARIO
					&& updater != DataType.LANDUSE_SCENARIO) {

				if (!modelPanel.checkTPM()) {
					JOptionPane
							.showMessageDialog(
									this,
									MenuProperty.MODEL_SCENARIO_TPM_INVALID.getAccessibleDescription(),
									MenuProperty.MODEL_SCENARIO_TPM_INVALID.getLabel(),
									JOptionPane.WARNING_MESSAGE);
				}
				
				ModelProject m = modelPanel.getProject().getModelProject();
				for (int i = 0; i < m.getIterationCount(); i++) {
					Project p = m.getSimulatedProject(i);
					AbacusModel.updateLanduseScenarioByTPM(p);
				}
			}
			this.fireTableDataChanged();
		}
	}

	public void updateLabel() {
		isScenarioUpdated = true;
		JTabbedPane tp = getTabPanel();
		int period = Integer.parseInt(tp.getTitleAt(tp.getSelectedIndex()));
		if (updatedPeriod >= 0 && period > updatedPeriod) {
			if (selectedPeriodIdx != tp.getSelectedIndex())
				JOptionPane
						.showMessageDialog(
								this,
								MenuProperty.MODEL_SCENARIO_CHANGE_EARLY.getLabel());
		} else if (updatedPeriod >= 0 && period < updatedPeriod) {
			if (selectedPeriodIdx != tp.getSelectedIndex())
				JOptionPane
						.showMessageDialog(
								this,
								MenuProperty.MODEL_SCENARIO_OVERWRITED.getLabel()+" "
										+ updatedPeriod
										+ " " + MenuProperty.MODEL_SCENARIO_OVERWRITED.getAccessibleDescription());
			updatedPeriod = period;
			updatedIndex = tp.getSelectedIndex();
		} else if (updatedPeriod < 0) {
			updatedPeriod = period;
			updatedIndex = tp.getSelectedIndex();
		}
		selectedPeriodIdx = tp.getSelectedIndex();
		warningLabel.setText(scenarioChange + updatedPeriod + scenarioChange2);
		modelPanel.updateScenario(updatedIndex, dataType);
	}

	public void setUpdateEnable(boolean b) {
		updateButton.setEnabled(b);
	}

	public void updateModelScenario() {
		if (dataType == DataType.TPM_SCENARIO) {
			ModelProject m = modelPanel.getProject().getModelProject();
			for (int i = 0; i < m.getIterationCount(); i++) {
				Project p = m.getSimulatedProject(i);
				AbacusModel.updateLanduseScenarioByTPM(p);
			}
		} else if (dataType == DataType.LANDUSE_SCENARIO) {
			ModelProject m = modelPanel.getProject().getModelProject();
			for (int i = 0; i < m.getIterationCount(); i++) {
				Project p = m.getSimulatedProject(i);
				AbacusModel.updateTPMbyLanduseScenario(p);
			}

		}
		modelPanel.updateModelScenario(updatedPeriod, dataType);
	}

	protected void resetLabel() {
		isScenarioUpdated = false;
		warningLabel.setText("");
		updatedPeriod = -1;
		updatedIndex = -1;
		updateButton.setEnabled(false);
	}

	public int getUpdatedPeriod() {
		return updatedPeriod;
	}

	public boolean isScenarioUpdated() {
		return isScenarioUpdated;
	}

	@Override
	public void setModelProject(ModelProject modelProject, DataType d,
			Object attributes) {
		if (modelProject == null || !modelProject.equals(updatedModel)) {
			if (!checkLeaveScenario())
				return;
		}
		super.setModelProject(modelProject, d, attributes);
		this.dataType = d;
		if (tabPanel.getTabCount() > 0)
			tabPanel.removeTabAt(tabPanel.getTabCount() - 1);
		for (int i = 0; i < getTabPanel().getTabCount(); i++) {
			getTabPanel().setTitleAt(i,Integer.toString(i+1));
		}
		setEditable(true);
		fireTableDataChanged();
		setScenarioUpdated(false);
		updatedModel = modelProject;
	}

	public void setScenarioUpdated(boolean isScenarioUpdated) {
		this.isScenarioUpdated = isScenarioUpdated;
	}

	private void setUnconvertedLanduse() {
		LCMatrixTabPanel mt = (LCMatrixTabPanel) tabPanel
				.getSelectedComponent();
		JTable table = mt.getSelectedPanel().getTable();
		int t = mt.getSelectedPanel().isTotalFields() ? 1 : 0;
//		double sum = 0;
//		for (int c = 0; c < table.getColumnCount() - t; c++) {
//			sum += (Double) mt.getSelectedPanel().getTable()
//					.getValueAt(selectedIndex, c);
//		}
		for (int c = 0; c < table.getColumnCount() - t; c++) {
			double v = 0;
			if (c == selectedIndex) {
				//v = sum;
				v=1;
			}
			mt.getSelectedPanel().getTable().setValueAt(v, selectedIndex, c);
		}
	}

	public void setProjectTreePanel(ProjectTreePanel p) {
		this.projectTreePanel = p;
		p.addProjectDockListener(listener);
	}

	public boolean isEnableMenu() {
		return isEnableMenu;
	}

	public void setEnableMenu(boolean isEnableMenu) {
		this.isEnableMenu = isEnableMenu;
	}

}
